package practice;

import practice.sort.QuickSort;

import java.util.*;

/**
 * 给定两个数组，写一个方法来计算它们的交集。
 * 例如:
 * 给定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].
 * <p>
 * 注意：
 * <p>
 * 输出结果中每个元素出现的次数，应与元素在两个数组中出现的次数一致。
 * 我们可以不考虑输出结果的顺序。
 * 跟进:
 * <p>
 * 如果给定的数组已经排好序呢？你将如何优化你的算法？
 * 如果 nums1 的大小比 nums2 小很多，哪种方法更优？
 * 如果nums2的元素存储在磁盘上，内存是有限的，你不能一次加载所有的元素到内存中，你该怎么办？
 */
public class _350_IntersectionOfTwoArrays2 {

    /**
     * 个人思路，先排序，再遍历
     *
     * @param nums1
     * @param nums2
     * @return
     */
    public static int[] intersect(int[] nums1, int[] nums2) {
        if (nums1.length == 0 || nums2.length == 0) {
            return new int[0];
        }
        List<Integer> result = new ArrayList<>();
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        fill(list1, nums1);
        fill(list2, nums2);
        Collections.sort(list1);
        Collections.sort(list2);
        for (int i = 0, j = 0; i < list1.size() && j < list2.size(); ) {
            int value1 = list1.get(i), value2 = list2.get(j);
            if (value1 > value2) {
                j++;
            } else if (value1 < value2) {
                i++;
            } else {
                i++;
                j++;
                result.add(value1);
            }
        }
        int[] res = new int[result.size()];
        for (int i = 0; i < result.size(); i++) {
            res[i] = result.get(i);
        }
        return res;
    }

    /**
     * 借鉴思路：先遍历第一个数组，再利用map存放个数，再遍历第2个数组，检查map，时间空间都为O(n)
     *
     * @param nums1
     * @param nums2
     * @return
     */
    public static int[] intersect1(int[] nums1, int[] nums2) {
        if (nums1.length == 0 || nums2.length == 0) {
            return new int[0];
        }
        Map<Integer, Integer> hashMap = new HashMap<>();
        List<Integer> resultList = new ArrayList<>();
        for (int i = 0; i < nums1.length; i++) {
            Integer value = nums1[i];
            Integer count = hashMap.get(value);
            if (count == null) {
                hashMap.put(value, 1);
            } else {
                hashMap.put(value, count + 1);
            }
        }
        for (int i = 0; i < nums2.length; i++) {
            int value = nums2[i];
            Integer count = hashMap.get(value);
            if (count != null) {
                resultList.add(value);
                hashMap.put(value, count == 1 ? null : count - 1);
            }
        }
        int index = 0;
        int[] result = new int[resultList.size()];
        for (Integer num : resultList) {
            result[index++] = num;
        }
        return result;
    }

    private static void fill(List list, int[] array) {
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
    }
}
